package service

import (
	"errors"
	"strconv"
	"time"

	"sieve_admin_server_userpass/pkg/im3/chatmsg"
	"sieve_admin_server_userpass/pkg/im3/data"
	"sieve_admin_server_userpass/pkg/im3/msgpack"
	"sieve_admin_server_userpass/pkg/json"
	"sieve_admin_server_userpass/pkg/mp/child"
)

func reqServer(api string, req interface{}, resp interface{}) error {
	b, err := msgpack.NewReq(api, req)
	if err != nil {
		return err
	}
	b, err = child.Request(b)
	if err != nil {
		return err
	}
	return msgpack.ParseResp(b, resp)
}

func postServer(api string, req interface{}) error {
	b, err := msgpack.NewReq(api, req)
	if err != nil {
		return err
	}
	return child.Post(b)
}

//

func addHttpHandler(path string, port int) error {
	resp := ""
	if err := reqServer("AddHttpHandler", map[string]interface{}{
		"Path": path,
		"Port": port,
	}, &resp); err != nil {
		return err
	}
	if resp != "OK" {
		return errors.New("failed")
	}
	return nil
}

func addMsgHandler(name string) error {
	resp := ""
	if err := reqServer("AddMsgHandler", map[string]string{"Name": name}, &resp); err != nil {
		return err
	}
	if resp != "OK" {
		return errors.New("failed")
	}
	return nil
}

//

type MsgOpt struct {
	Sync       bool  `json:",omitempty"`
	Notice     bool  `json:",omitempty"`
	IgnoreUid  int   `json:",omitempty"`
	IgnoreConn int64 `json:",omitempty"`
}

func SendToUsers(uids []int, msg_name string, msg_data interface{}, opt *MsgOpt) (msgid int64, err error) {
	if opt == nil {
		opt = &MsgOpt{}
	}
	req := map[string]interface{}{
		"Uids": uids,
		"Name": msg_name,
		"Msg":  msg_data,
		"Opt":  opt,
	}
	if opt.Sync {
		err = reqServer("SendToUsers", req, &msgid)
	} else {
		err = postServer("SendToUsers", req)
	}
	return
}

func SendToUser(uid int, msg_name string, msg_data interface{}, opt *MsgOpt) (msgid int64, err error) {
	return SendToUsers([]int{uid}, msg_name, msg_data, opt)
}

func SendToGroup(gid int, msg_name string, msg_data interface{}, opt *MsgOpt) (msgid int64, err error) {
	// if gid == 0 {
	// 	return SendToAll(msg_name, msg_data, opt)
	// }
	uids, err := data.GetGroupUids(gid)
	if err != nil {
		return 0, err
	}
	return SendToUsers(uids, msg_name, msg_data, opt)
}

func SendToUnit(unit int, msg_name string, msg_data interface{}, opt *MsgOpt) (msgid int64, err error) {
	uids, err := data.GetUnitUids(unit)
	if err != nil {
		return 0, err
	}
	return SendToUsers(uids, msg_name, msg_data, opt)
}

func SendToAll(msg_name string, msg_data interface{}, opt *MsgOpt) (msgid int64, err error) {
	if opt == nil {
		opt = &MsgOpt{}
	}
	req := map[string]interface{}{
		"Name": msg_name,
		"Msg":  msg_data,
		"Opt":  opt,
	}
	if opt.Sync {
		err = reqServer("SendToAll", req, &msgid)
	} else {
		err = postServer("SendToAll", req)
	}
	return
}

func SendToOnline(msg_name string, msg_data interface{}, opt *MsgOpt) error {
	return postServer("SendToOnline", map[string]interface{}{
		"Name": msg_name,
		"Msg":  msg_data,
		"Opt":  opt,
	})
}

func SendToConn(uid int, conn int64, msg_name string, msg_data interface{}) error {
	return postServer("SendToConn", map[string]interface{}{
		"Uid":  uid,
		"Conn": conn,
		"Name": msg_name,
		"Msg":  msg_data,
	})
}

//

func DisconnectUser(uid int, text string, opt *MsgOpt) error {
	return postServer("Disconnect", map[string]interface{}{
		"Uid":  uid,
		"Text": text,
		"Opt":  opt,
	})
}

//

type ccMessage struct {
	Id     int64
	ID     string
	From   int
	Target int
	To     int
	STime  int64
	CTime  int64
	Data   string
	Key    string
	SKey   string
	Sign   string
}

func newChatMsg(target, to int, msg *chatmsg.Msg) (*ccMessage, error) {
	now := time.Now()
	data, err := json.Marshal(msg)
	if err != nil {
		return nil, err
	}
	id := (now.UnixNano() / 1000000) * 10000
	return &ccMessage{
		Id:     id,
		ID:     strconv.FormatInt(id, 10),
		From:   0,
		Target: target,
		To:     to,
		CTime:  now.Unix(),
		STime:  now.Unix(),
		Data:   string(data),
		Key:    "",
		SKey:   "",
		Sign:   "",
	}, nil
}

func SendChatToUser(uid int, msg *chatmsg.Msg) (int64, error) {
	data, err := newChatMsg(1, uid, msg)
	if err != nil {
		return 0, err
	}
	return SendToUser(uid, "CCMessage", data, &MsgOpt{Sync: true, Notice: true})
}

func SendChatToGroup(gid int, msg *chatmsg.Msg) (int64, error) {
	data, err := newChatMsg(2, gid, msg)
	if err != nil {
		return 0, err
	}
	return SendToGroup(gid, "CCMessage", data, &MsgOpt{Sync: true, Notice: true})
}

func SendChatToUnit(unit int, msg *chatmsg.Msg) (int64, error) {
	data, err := newChatMsg(3, unit, msg)
	if err != nil {
		return 0, err
	}
	return SendToUnit(unit, "CCMessage", data, &MsgOpt{Sync: true, Notice: true})
}

//

type scSysMsg struct {
	Name  string
	STime int64
	Key   string
	Data  string
}

func newSysMsg(name string, msg *chatmsg.Msg) (*scSysMsg, error) {
	data, err := json.Marshal(msg)
	if err != nil {
		return nil, err
	}
	return &scSysMsg{
		Name:  name,
		STime: time.Now().Unix(),
		Data:  string(data),
		Key:   "",
	}, nil
}

func SendSysMsgToUser(uid int, name string, msg *chatmsg.Msg) error {
	data, err := newSysMsg(name, msg)
	if err != nil {
		return err
	}
	_, err = SendToUser(uid, "SCSysMsg", data, &MsgOpt{Sync: true, Notice: true})
	return err
}

func SendSysMsgToUsers(uids []int, name string, msg *chatmsg.Msg) error {
	data, err := newSysMsg(name, msg)
	if err != nil {
		return err
	}
	_, err = SendToUsers(uids, "SCSysMsg", data, &MsgOpt{Sync: true, Notice: true})
	return err
}

func SendSysMsgToGroup(gid int, name string, msg *chatmsg.Msg) error {
	data, err := newSysMsg(name, msg)
	if err != nil {
		return err
	}
	_, err = SendToGroup(gid, "SCSysMsg", data, &MsgOpt{Sync: true, Notice: true})
	return err
}

func SendSysMsgToUnit(unit int, name string, msg *chatmsg.Msg) error {
	data, err := newSysMsg(name, msg)
	if err != nil {
		return err
	}
	_, err = SendToUnit(unit, "SCSysMsg", data, &MsgOpt{Sync: true, Notice: true})
	return err
}

func SendSysMsgToAll(name string, msg *chatmsg.Msg) error {
	data, err := newSysMsg(name, msg)
	if err != nil {
		return err
	}
	_, err = SendToAll("SCSysMsg", data, &MsgOpt{Sync: true, Notice: true})
	return err
}

//

type svcApiData struct {
	Svc  string
	Api  string
	Data interface{}
}

func ReqSvc(svc string, api string, req interface{}, resp interface{}) error {
	return reqServer("ReqSvc", &svcApiData{
		Svc:  svc,
		Api:  api,
		Data: req,
	}, &resp)
}

func PostSvc(svc string, api string, req interface{}) error {
	return postServer("PostSvc", &svcApiData{
		Svc:  svc,
		Api:  api,
		Data: req,
	})
}

// func TestTest(t string) (string, error) {
// 	ret := ""
// 	err := ReqSvc("test", "Test", map[string]string{"T": t}, &ret)
// 	return ret, err
// }

func DumpServer() (string, error) {
	data := ""
	err := reqServer("Dump", map[string]int{}, &data)
	return data, err
}

type DumpUser struct {
	Uid   int
	Conns []*DumpConn
}

type DumpConn struct {
	Id      int64
	RAddr   string
	RLAddr  string
	Suffix  int
	Status  int
	LogId   int64
	Connect int64
	Pf      string
	Ver     string
}

func DumpUsers(uids []int) ([]*DumpUser, error) {
	list := []*DumpUser{}
	err := reqServer("DumpUsers", map[string]interface{}{"Uids": uids}, &list)
	return list, err
}

// svc-event only
func GetServerEventPwd() (string, error) {
	data := ""
	err := reqServer("GetServerEventPwd", map[string]int{}, &data)
	return data, err
}
